import socket,select
from typing import ItemsView
import os
from concurrent.futures import ThreadPoolExecutor
import threading

waitingWork=[] #存放待处理套接字
waitingWorkMutex=threading.Lock()
newWorkEvent=threading.Event()

MAXTHREADNUM=10

def getPort():
    return 7777


def service(socket):
    username=None
    password=None
    currentDir="C:/Users/Shinelon/Desktop/网络编程练习/ch5ip/root/ftproot/"
    while(True):
        try:
            readable,_,_=select.select([socket],[],[])
            for sk in readable:
                packet=str(sk.recv(65535),encoding="utf-8")
                items=packet.split("\r\n",3)
                command=items[0]
                if(command=="USER"):
                    username=items[1]
                elif(command=="PASS"):
                    password=items[1]
                elif(command=="QUIT"):
                    sk.close()
                    return 
                elif(command=="PWD"):
                    sk.send(bytes(currentDir,encoding="utf-8"))
                elif(command=="CWD"):
                    currentDir+=items[1]
                elif(command=="MKD"):
                    newDir=items[1]
                    os.makedirs(currentDir+newDir)
                elif(command=="RMD"):
                    removeDir=items[1]
                    os.removedirs(currentDir+removeDir)
                elif(command=="DELE"):
                    removeFile=items[1]
                    os.remove(currentDir+removeFile)
                elif(command=="SIZE"):
                    wantFile=items[1]
                    size=os.stat(currentDir+wantFile).st_size
                    sk.send(bytes(size+"B",encoding="utf-8"))
                elif(command=="PASV"):
                    port=getPort()
                    sk.send(bytes(port,encoding="utf-8"))
                elif(command=="PORT"):
                    pass
                elif(command=="LIST"):
                    sk.send(bytes(os.listdir(currentDir),encoding="utf-8"))
                elif(command=="RETR"):
                    downloadFile=items[1]
                    with open(currentDir+downloadFile,"rb") as f:
                        sk.send(bytes(str(os.stat(currentDir+downloadFile).st_size)+"\r\n",encoding="utf-8")+f.read())
                    sk.send(bytes("RETR SUCCESS",encoding="utf-8"))
                elif(command=="STOR"):
                    storeFileName=items[1]
                    storeData=""
                    fileSize=int(items[2])
                    storeData+=items[3]
                    while( fileSize > len(storeData) ):
                        packet=socket.recv(65535)
                        storeData+=str( sk.recv(65535) , encoding="utf-8" )
                    with open(currentDir+storeFileName,"w") as f:
                        f.write(storeData)
                    sk.send(bytes("STOR SUCCESS",encoding="utf-8"))
                elif( command == "REST" ):
                    pass
                elif( command == "APPE" ):
                    pass
                else:
                    socket.send(bytes("NO SUCH COMMAND",encoding="utf-8"))
        except Exception as e:
            print(e)
            socket.close()

                
def findWork():
    while(True):
        newWorkEvent.wait()
        work=None
        waitingWorkMutex.acquire()
        if(waitingWork):
            work=waitingWork.pop()
        waitingWorkMutex.release()
        if(work!=None):
            service(work)

def daemon():
    while(True):
        if(waitingWork):
            newWorkEvent.set()
        else:
            newWorkEvent.clear()


HOST,PORT=socket.gethostbyname(socket.gethostname()),6666
if __name__=="__main__":
    listenTcpSocket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    listenTcpSocket.bind((HOST,PORT))
    listenTcpSocket.listen()

    threading.Thread(target=daemon).start()

    threads=[threading.Thread(target=findWork) for i in range(MAXTHREADNUM)]
    for thread in threads:
        thread.start()

    while(True):
        readable,_,_=select.select([listenTcpSocket],[],[])
        for sk in readable:
            clientSocket,clientAddr=sk.accept()   
            waitingWorkMutex.acquire()
            waitingWork.append(clientSocket)
            waitingWorkMutex.release()